{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "afefe24b",
   "metadata": {
    "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
    "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:29.485100Z",
     "iopub.status.busy": "2024-09-15T23:49:29.484388Z",
     "iopub.status.idle": "2024-09-15T23:49:31.395884Z",
     "shell.execute_reply": "2024-09-15T23:49:31.395087Z"
    },
    "papermill": {
     "duration": 1.923404,
     "end_time": "2024-09-15T23:49:31.398253",
     "exception": false,
     "start_time": "2024-09-15T23:49:29.474849",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import glob\n",
    "\n",
    "import mne\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from tqdm.auto import tqdm\n",
    "from sklearn.model_selection import train_test_split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b59a9cd9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:31.415928Z",
     "iopub.status.busy": "2024-09-15T23:49:31.415025Z",
     "iopub.status.idle": "2024-09-15T23:49:31.428368Z",
     "shell.execute_reply": "2024-09-15T23:49:31.427608Z"
    },
    "papermill": {
     "duration": 0.024276,
     "end_time": "2024-09-15T23:49:31.430341",
     "exception": false,
     "start_time": "2024-09-15T23:49:31.406065",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "data_dir = \"/kaggle/input/ppg-dalia-processed\"\n",
    "filepaths = glob.glob(os.path.join(data_dir, \"*.npz\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "df071cc4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:31.446224Z",
     "iopub.status.busy": "2024-09-15T23:49:31.445870Z",
     "iopub.status.idle": "2024-09-15T23:49:31.453358Z",
     "shell.execute_reply": "2024-09-15T23:49:31.452458Z"
    },
    "papermill": {
     "duration": 0.01763,
     "end_time": "2024-09-15T23:49:31.455311",
     "exception": false,
     "start_time": "2024-09-15T23:49:31.437681",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 80-20-20\n",
    "train_files, test_files = train_test_split(filepaths, test_size=0.2, shuffle=True, random_state=42)\n",
    "val_files, test_files = train_test_split(test_files, test_size=0.5, shuffle=True, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "84f0fefd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:31.471175Z",
     "iopub.status.busy": "2024-09-15T23:49:31.470821Z",
     "iopub.status.idle": "2024-09-15T23:49:31.741587Z",
     "shell.execute_reply": "2024-09-15T23:49:31.740777Z"
    },
    "papermill": {
     "duration": 0.281092,
     "end_time": "2024-09-15T23:49:31.743843",
     "exception": false,
     "start_time": "2024-09-15T23:49:31.462751",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "labels = []\n",
    "\n",
    "for file in train_files:\n",
    "    labels.append(np.load(file)[\"label\"])\n",
    "    \n",
    "labels = np.concatenate(labels)\n",
    "mean, std = labels.mean(), labels.std()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b91bf5a",
   "metadata": {
    "papermill": {
     "duration": 0.007252,
     "end_time": "2024-09-15T23:49:31.758690",
     "exception": false,
     "start_time": "2024-09-15T23:49:31.751438",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "- Dataset & Dataloader\n",
    "- Training\n",
    "- Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6a5e2fe2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:31.774370Z",
     "iopub.status.busy": "2024-09-15T23:49:31.774022Z",
     "iopub.status.idle": "2024-09-15T23:49:46.513115Z",
     "shell.execute_reply": "2024-09-15T23:49:46.512146Z"
    },
    "papermill": {
     "duration": 14.749368,
     "end_time": "2024-09-15T23:49:46.515248",
     "exception": false,
     "start_time": "2024-09-15T23:49:31.765880",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7bf26fd06b7b4201bd6adb373755326b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/12 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "train_ecg = []\n",
    "train_ppg = []\n",
    "train_labels = []\n",
    "\n",
    "for file in tqdm(train_files):\n",
    "    data = np.load(file)\n",
    "    ecg = data[\"ecg\"]\n",
    "    ppg = data[\"ppg\"]\n",
    "    label = data[\"label\"]\n",
    "    \n",
    "    ecg_resampled = mne.filter.resample(ecg.astype(float), down=700/64)\n",
    "    train_ecg.append(ecg_resampled)\n",
    "    train_ppg.append(ppg)\n",
    "    train_labels.append(label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1ed6e36c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:46.532808Z",
     "iopub.status.busy": "2024-09-15T23:49:46.531898Z",
     "iopub.status.idle": "2024-09-15T23:49:47.717446Z",
     "shell.execute_reply": "2024-09-15T23:49:47.716526Z"
    },
    "papermill": {
     "duration": 1.197209,
     "end_time": "2024-09-15T23:49:47.720451",
     "exception": false,
     "start_time": "2024-09-15T23:49:46.523242",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d9d817444e2f4a0299cb21059f84c2b2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "val_ecg = []\n",
    "val_ppg = []\n",
    "val_labels = []\n",
    "\n",
    "for file in tqdm(val_files):\n",
    "    data = np.load(file)\n",
    "    ecg = data[\"ecg\"]\n",
    "    ppg = data[\"ppg\"]\n",
    "    label = data[\"label\"]\n",
    "    \n",
    "    ecg_resampled = mne.filter.resample(ecg.astype(float), down=700/64)\n",
    "    val_ecg.append(ecg_resampled)\n",
    "    val_ppg.append(ppg)\n",
    "    val_labels.append(label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c66ae649",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:47.737482Z",
     "iopub.status.busy": "2024-09-15T23:49:47.737138Z",
     "iopub.status.idle": "2024-09-15T23:49:47.877967Z",
     "shell.execute_reply": "2024-09-15T23:49:47.877156Z"
    },
    "papermill": {
     "duration": 0.151995,
     "end_time": "2024-09-15T23:49:47.880362",
     "exception": false,
     "start_time": "2024-09-15T23:49:47.728367",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_ecg = np.concatenate(train_ecg, axis=0)\n",
    "val_ecg = np.concatenate(val_ecg, axis=0)\n",
    "\n",
    "train_ppg = np.concatenate(train_ppg, axis=0)\n",
    "val_ppg = np.concatenate(val_ppg, axis=0)\n",
    "\n",
    "train_labels = np.concatenate(train_labels, axis=0)\n",
    "val_labels = np.concatenate(val_labels, axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "826d7fe8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:47.897599Z",
     "iopub.status.busy": "2024-09-15T23:49:47.897246Z",
     "iopub.status.idle": "2024-09-15T23:49:48.128587Z",
     "shell.execute_reply": "2024-09-15T23:49:48.127592Z"
    },
    "papermill": {
     "duration": 0.242604,
     "end_time": "2024-09-15T23:49:48.131046",
     "exception": false,
     "start_time": "2024-09-15T23:49:47.888442",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_ecg = (train_ecg - np.min(train_ecg)) / (np.max(train_ecg) - np.min(train_ecg))\n",
    "train_ppg = (train_ppg - np.min(train_ppg)) / (np.max(train_ppg) - np.min(train_ppg))\n",
    "\n",
    "val_ecg = (val_ecg - np.min(val_ecg)) / (np.max(val_ecg) - np.min(val_ecg))\n",
    "val_ppg = (val_ppg - np.min(val_ppg)) / (np.max(val_ppg) - np.min(val_ppg))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "34f4f23b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:48.149414Z",
     "iopub.status.busy": "2024-09-15T23:49:48.149023Z",
     "iopub.status.idle": "2024-09-15T23:49:48.155069Z",
     "shell.execute_reply": "2024-09-15T23:49:48.154286Z"
    },
    "papermill": {
     "duration": 0.017424,
     "end_time": "2024-09-15T23:49:48.157194",
     "exception": false,
     "start_time": "2024-09-15T23:49:48.139770",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def normalize_labels(label):\n",
    "    return (label - mean) / std\n",
    "\n",
    "def unnormalize_labels(label):\n",
    "    return std * label + mean\n",
    "\n",
    "mean, std = train_labels.mean(), train_labels.std()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ea189bf9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:48.174740Z",
     "iopub.status.busy": "2024-09-15T23:49:48.173912Z",
     "iopub.status.idle": "2024-09-15T23:49:51.434142Z",
     "shell.execute_reply": "2024-09-15T23:49:51.433272Z"
    },
    "papermill": {
     "duration": 3.271115,
     "end_time": "2024-09-15T23:49:51.436472",
     "exception": false,
     "start_time": "2024-09-15T23:49:48.165357",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import torch.nn.functional as F\n",
    "\n",
    "from torch.utils.data import TensorDataset, DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2fe5c509",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.454189Z",
     "iopub.status.busy": "2024-09-15T23:49:51.453648Z",
     "iopub.status.idle": "2024-09-15T23:49:51.565456Z",
     "shell.execute_reply": "2024-09-15T23:49:51.564553Z"
    },
    "papermill": {
     "duration": 0.123037,
     "end_time": "2024-09-15T23:49:51.567983",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.444946",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_ecg = torch.tensor(train_ecg, dtype=torch.float32)\n",
    "train_ppg = torch.tensor(train_ppg, dtype=torch.float32)\n",
    "train_labels = torch.tensor(train_labels, dtype=torch.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "88c5d25a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.586388Z",
     "iopub.status.busy": "2024-09-15T23:49:51.585584Z",
     "iopub.status.idle": "2024-09-15T23:49:51.597699Z",
     "shell.execute_reply": "2024-09-15T23:49:51.596714Z"
    },
    "papermill": {
     "duration": 0.023813,
     "end_time": "2024-09-15T23:49:51.599992",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.576179",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_ecg = train_ecg.unsqueeze(dim=-2)\n",
    "train_ppg = train_ppg.unsqueeze(dim=-2)\n",
    "train_labels = train_labels.unsqueeze(dim=-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "1310c5ff",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.620608Z",
     "iopub.status.busy": "2024-09-15T23:49:51.619608Z",
     "iopub.status.idle": "2024-09-15T23:49:51.633901Z",
     "shell.execute_reply": "2024-09-15T23:49:51.632912Z"
    },
    "papermill": {
     "duration": 0.026419,
     "end_time": "2024-09-15T23:49:51.636056",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.609637",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_labels_normalized = normalize_labels(train_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "51a6e1d3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.652852Z",
     "iopub.status.busy": "2024-09-15T23:49:51.652496Z",
     "iopub.status.idle": "2024-09-15T23:49:51.657776Z",
     "shell.execute_reply": "2024-09-15T23:49:51.656850Z"
    },
    "papermill": {
     "duration": 0.015901,
     "end_time": "2024-09-15T23:49:51.659740",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.643839",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "batch_size = 128\n",
    "\n",
    "train_dataset = TensorDataset(train_ecg, train_ppg, train_labels_normalized)\n",
    "train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "66df9770",
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.676079Z",
     "iopub.status.busy": "2024-09-15T23:49:51.675724Z",
     "iopub.status.idle": "2024-09-15T23:49:51.819399Z",
     "shell.execute_reply": "2024-09-15T23:49:51.818424Z"
    },
    "papermill": {
     "duration": 0.154421,
     "end_time": "2024-09-15T23:49:51.821677",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.667256",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class BasicBlock(nn.Module):\n",
    "    expansion = 1\n",
    "\n",
    "    def __init__(self, in_planes, planes, stride=1):\n",
    "        super(BasicBlock, self).__init__()\n",
    "        self.conv1 = nn.Conv1d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)\n",
    "        self.bn1 = nn.BatchNorm1d(planes)\n",
    "        self.conv2 = nn.Conv1d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)\n",
    "        self.bn2 = nn.BatchNorm1d(planes)\n",
    "\n",
    "        self.shortcut = nn.Sequential()\n",
    "        if stride != 1 or in_planes != self.expansion*planes:\n",
    "            self.shortcut = nn.Sequential(\n",
    "                nn.Conv1d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),\n",
    "                nn.BatchNorm1d(self.expansion*planes)\n",
    "            )\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = F.relu(self.bn1(self.conv1(x)))\n",
    "        out = self.bn2(self.conv2(out))\n",
    "        out += self.shortcut(x)\n",
    "        out = F.relu(out)\n",
    "        return out\n",
    "\n",
    "\n",
    "\n",
    "class Bottleneck(nn.Module):\n",
    "    expansion = 4\n",
    "\n",
    "    def __init__(self, in_planes, planes, stride=1):\n",
    "        super(Bottleneck, self).__init__()\n",
    "        self.conv1 = nn.Conv1d(in_planes, planes, kernel_size=1, bias=False)\n",
    "        self.bn1 = nn.BatchNorm1d(planes)\n",
    "        self.conv2 = nn.Conv1d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)\n",
    "        self.bn2 = nn.BatchNorm1d(planes)\n",
    "        self.conv3 = nn.Conv1d(planes, self.expansion*planes, kernel_size=1, bias=False)\n",
    "        self.bn3 = nn.BatchNorm1d(self.expansion*planes)\n",
    "\n",
    "        self.shortcut = nn.Sequential()\n",
    "        if stride != 1 or in_planes != self.expansion*planes:\n",
    "            self.shortcut = nn.Sequential(\n",
    "                nn.Conv1d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),\n",
    "                nn.BatchNorm1d(self.expansion*planes)\n",
    "            )\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = F.relu(self.bn1(self.conv1(x)))\n",
    "        out = F.relu(self.bn2(self.conv2(out)))\n",
    "        out = self.bn3(self.conv3(out))\n",
    "        out += self.shortcut(x)\n",
    "        out = F.relu(out)\n",
    "        return out\n",
    "\n",
    "\n",
    "class ResNet(nn.Module):\n",
    "    def __init__(self, block, num_blocks, num_classes=2):\n",
    "        super(ResNet, self).__init__()\n",
    "        self.in_planes = 48\n",
    "\n",
    "        self.conv0 = nn.Conv1d(1, 48, kernel_size=80, stride=4)\n",
    "        self.bn1 = nn.BatchNorm1d(48)\n",
    "        self.stage0 = self._make_layer(block, 48, num_blocks[0], stride=1)\n",
    "        self.stage1 = self._make_layer(block, 96, num_blocks[1], stride=2)\n",
    "        self.stage2 = self._make_layer(block, 192, num_blocks[2], stride=2)\n",
    "        self.stage3 = self._make_layer(block, 384, num_blocks[3], stride=2)\n",
    "        self.fc = nn.Linear(384*block.expansion, num_classes)\n",
    "\n",
    "\n",
    "    def _make_layer(self, block, planes, num_blocks, stride):\n",
    "        strides = [stride] + [1]*(num_blocks-1)\n",
    "        layers = []\n",
    "        for stride in strides:\n",
    "            layers.append(block(self.in_planes, planes, stride))\n",
    "            self.in_planes = planes * block.expansion\n",
    "        return nn.Sequential(*layers)\n",
    "\n",
    "\n",
    "    def forward(self, x):\n",
    "        \n",
    "        out = self.conv0(x)\n",
    "        out = self.bn1(out)\n",
    "        out = F.relu(out)\n",
    "        out = self.stage0(out)\n",
    "        out = self.stage1(out)\n",
    "        out = self.stage2(out)\n",
    "        out = self.stage3(out)\n",
    "        out = F.avg_pool1d(out, 1)\n",
    "        \n",
    "        features = out.mean(dim=2)\n",
    "        out = self.fc(features)\n",
    "        \n",
    "        return out, features\n",
    "\n",
    "\n",
    "\n",
    "def ResNet18(num_classes=2):\n",
    "    return ResNet(BasicBlock, [2,2,2,2], num_classes=num_classes)\n",
    "\n",
    "def ResNet34(num_classes=2):\n",
    "    return ResNet(BasicBlock, [3,4,6,3], num_classes=num_classes)\n",
    "\n",
    "def ResNet50(num_classes=2):\n",
    "    return ResNet(Bottleneck, [3,4,6,3], num_classes=num_classes)\n",
    "\n",
    "def ResNet101(num_classes=2):\n",
    "    return ResNet(Bottleneck, [3,4,23,3], num_classes=num_classes)\n",
    "\n",
    "def ResNet152(num_classes=2):\n",
    "    return ResNet(Bottleneck, [3,8,36,3], num_classes=num_classes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "8b3bfe55",
   "metadata": {
    "_kg_hide-input": true,
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.840604Z",
     "iopub.status.busy": "2024-09-15T23:49:51.840243Z",
     "iopub.status.idle": "2024-09-15T23:49:51.905556Z",
     "shell.execute_reply": "2024-09-15T23:49:51.904551Z"
    },
    "papermill": {
     "duration": 0.076929,
     "end_time": "2024-09-15T23:49:51.908094",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.831165",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class ResBlock(nn.Module):\n",
    "\n",
    "    def __init__(self, filters, stage, i_block, kernel_size=3, stride=1):\n",
    "        super(ResBlock,self).__init__()\n",
    "        self.out_channels = filters\n",
    "        self.kernel_size = kernel_size\n",
    "        self.stride = stride\n",
    "        self.in_channels = filters\n",
    "\n",
    "        if i_block == 0 and stage != 0:\n",
    "            self.in_channels = filters // 2\n",
    "\n",
    "        self.conv1 = nn.Conv1d(\n",
    "            in_channels=self.in_channels,\n",
    "            out_channels=self.out_channels,\n",
    "            kernel_size=self.kernel_size,\n",
    "            stride=self.stride,\n",
    "            padding='same')\n",
    "        self.bn1 = nn.BatchNorm1d(self.out_channels)\n",
    "        self.relu1 = nn.ReLU()\n",
    "\n",
    "        self.conv2 = nn.Conv1d(\n",
    "            in_channels=self.out_channels,\n",
    "            out_channels=self.out_channels,\n",
    "            kernel_size=self.kernel_size,\n",
    "            stride=self.stride,\n",
    "            padding='same')\n",
    "\n",
    "        self.bn2 = nn.BatchNorm1d(self.out_channels)\n",
    "        self.bn3 = nn.BatchNorm1d(self.out_channels)\n",
    "        self.relu2 = nn.ReLU()\n",
    "\n",
    "    def forward(self, x):\n",
    "\n",
    "        out = x\n",
    "        out = self.relu1(self.bn1(self.conv1(out)))\n",
    "        out = self.bn2(self.conv2(out))\n",
    "        if x.shape[1] != out.shape[1]:\n",
    "            out = torch.add(out, torch.repeat_interleave(x, 2, dim=1))\n",
    "        else:\n",
    "            out = torch.add(out, x)\n",
    "\n",
    "        out = self.relu2(self.bn3(out))\n",
    "\n",
    "        return out\n",
    "\n",
    "\n",
    "\n",
    "class Resnet34Baseline(nn.Module):\n",
    "    def __init__(self, num_classes=2):\n",
    "        super(Resnet34Baseline,self).__init__()\n",
    "        self.num_classes = num_classes\n",
    "        self.conv0 = nn.Conv1d(1, 48, 80, 4)\n",
    "        self.bn0 = nn.BatchNorm1d(48)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.pool0 = nn.MaxPool1d(4)\n",
    "        self.stage0 = nn.Sequential(ResBlock(48, 0, 0),\n",
    "                                   ResBlock(48, 0, 1))\n",
    "        self.pool1 = nn.MaxPool1d(4)\n",
    "        self.stage1 = nn.Sequential(ResBlock(96, 1, 0),\n",
    "                                   ResBlock(96, 1, 1))\n",
    "        self.pool2 = nn.MaxPool1d(4)\n",
    "        self.stage2 = nn.Sequential(ResBlock(192, 2, 0),\n",
    "                                    ResBlock(192, 2, 1))\n",
    "        self.pool3 = nn.MaxPool1d(4)\n",
    "        self.stage3 = nn.Sequential(ResBlock(384, 3, 0),\n",
    "                                    ResBlock(384, 3, 1))\n",
    "\n",
    "        self.avgpool = nn.AvgPool1d(1)\n",
    "        self.dense1 = nn.Linear(384, self.num_classes)\n",
    "\n",
    "    def forward(self, x, placeholder):\n",
    "        \n",
    "        out = self.conv0(x)\n",
    "        out = self.bn0(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.pool0(out)\n",
    "\n",
    "\n",
    "        out = self.stage0(out)\n",
    "        out = self.pool1(out)\n",
    "\n",
    "        out = self.stage1(out)\n",
    "        out = self.pool2(out)\n",
    "\n",
    "\n",
    "        out = self.stage2(out)\n",
    "        out = self.pool3(out)\n",
    "\n",
    "\n",
    "        out = self.stage3(out)\n",
    "\n",
    "\n",
    "        out = self.avgpool(out)\n",
    "        features = out.mean(dim=2)\n",
    "\n",
    "        out = self.dense1(features)\n",
    "\n",
    "        return features, out\n",
    "\n",
    "\n",
    "class Resnet34(nn.Module):\n",
    "    def __init__(self, num_classes=2):\n",
    "        super(Resnet34,self).__init__()\n",
    "        self.num_classes = num_classes\n",
    "        self.conv0 = nn.Conv1d(1, 48, 7, 2)\n",
    "        self.bn0 = nn.BatchNorm1d(48)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.pool0 = nn.MaxPool1d(2)\n",
    "        self.stage0 = nn.Sequential(ResBlock(48, 0, 0),\n",
    "                                   ResBlock(48, 0, 1))\n",
    "        self.pool1 = nn.MaxPool1d(2)\n",
    "        self.stage1 = nn.Sequential(ResBlock(96, 1, 0),\n",
    "                                   ResBlock(96, 1, 1))\n",
    "        self.pool2 = nn.MaxPool1d(2)\n",
    "        self.stage2 = nn.Sequential(ResBlock(192, 2, 0),\n",
    "                                    ResBlock(192, 2, 1))\n",
    "        self.pool3 = nn.MaxPool1d(2)\n",
    "        self.stage3 = nn.Sequential(ResBlock(384, 3, 0),\n",
    "                                    ResBlock(384, 3, 1))\n",
    "\n",
    "        self.avgpool = nn.AvgPool1d(1)\n",
    "        self.fc = nn.Linear(384, self.num_classes)\n",
    "\n",
    "    def forward(self, x):\n",
    "        \n",
    "        out = self.conv0(x)\n",
    "        out = self.bn0(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.pool0(out)\n",
    "\n",
    "\n",
    "        out = self.stage0(out)\n",
    "        out = self.pool1(out)\n",
    "\n",
    "        out = self.stage1(out)\n",
    "        out = self.pool2(out)\n",
    "\n",
    "\n",
    "        out = self.stage2(out)\n",
    "        out = self.pool3(out)\n",
    "\n",
    "\n",
    "        out = self.stage3(out)\n",
    "\n",
    "\n",
    "        out = self.avgpool(out)\n",
    "        features = out.mean(dim=2)\n",
    "        out = self.fc(features)\n",
    "\n",
    "        return out, features\n",
    "\n",
    "\n",
    "class DirectFwd(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(DirectFwd, self).__init__()\n",
    "\n",
    "    def forward(self, x):\n",
    "        return x\n",
    "\n",
    "\n",
    "class Res34SimSiam(nn.Module):\n",
    "    \"\"\"\n",
    "    Build a SimSiam model.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim=2048, pred_dim=512, predictor=True):\n",
    "        \"\"\"\n",
    "        dim: feature dimension (default: 2048)\n",
    "        pred_dim: hidden dimension of the predictor (default: 512)\n",
    "        \"\"\"\n",
    "        super(Res34SimSiam, self).__init__()\n",
    "\n",
    "        # create the encoder\n",
    "        # num_classes is the output fc dimension, zero-initialize last BNs\n",
    "        self.encoder = Resnet34(num_classes=dim)\n",
    "        # build a 3-layer projector\n",
    "        prev_dim = self.encoder.fc.weight.shape[1]\n",
    "        self.encoder.fc = nn.Sequential(nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # first layer\n",
    "                                        nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # second layer\n",
    "                                        self.encoder.fc,\n",
    "                                        nn.BatchNorm1d(dim, affine=False)) # output layer\n",
    "        self.encoder.fc[6].bias.requires_grad = False # hack: not use bias as it is followed by BN\n",
    "\n",
    "        if predictor:\n",
    "        # build a 2-layer predictor\n",
    "            self.predictor = nn.Sequential(nn.Linear(dim, pred_dim, bias=False),\n",
    "                                            nn.BatchNorm1d(pred_dim),\n",
    "                                            nn.ReLU(inplace=True), # hidden layer\n",
    "                                            nn.Linear(pred_dim, dim)) # output layer\n",
    "        else:\n",
    "            self.predictor = DirectFwd()\n",
    "\n",
    "        self.regression_head = nn.Linear(384, 1)\n",
    "\n",
    "    def forward(self, ECG, PPG):\n",
    "        \"\"\"\n",
    "        Input:\n",
    "            x1: first views of images\n",
    "            x2: second views of images\n",
    "        Output:\n",
    "            p1, p2, z1, z2: predictors and targets of the network\n",
    "            See Sec. 3 of https://arxiv.org/abs/2011.10566 for detailed notations\n",
    "        \"\"\"\n",
    "        # compute features for one view\n",
    "        z1, features1 = self.encoder(ECG) # NxC\n",
    "        z2, features2 = self.encoder(PPG) # NxC\n",
    "\n",
    "        p1 = self.predictor(z1) # NxC\n",
    "        p2 = self.predictor(z2) # NxC\n",
    "\n",
    "        reg_pred1 = self.regression_head(features1)\n",
    "        reg_pred2 = self.regression_head(features2)\n",
    "\n",
    "        return p1, p2, z1.detach(), z2.detach(), reg_pred1, reg_pred2\n",
    "\n",
    "\n",
    "class Res50SimSiam(nn.Module):\n",
    "    \"\"\"\n",
    "    Build a SimSiam model.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim=2048, pred_dim=512, predictor=True, single_source_mode=False):\n",
    "        \"\"\"\n",
    "        dim: feature dimension (default: 2048)\n",
    "        pred_dim: hidden dimension of the predictor (default: 512)\n",
    "        \"\"\"\n",
    "        super(Res50SimSiam, self).__init__()\n",
    "\n",
    "        # create the encoder\n",
    "        # num_classes is the output fc dimension, zero-initialize last BNs\n",
    "        self.encoder = ResNet50(num_classes=dim)\n",
    "        self.single_source_mode = single_source_mode\n",
    "        # build a 3-layer projector\n",
    "        prev_dim = self.encoder.fc.weight.shape[1]\n",
    "\n",
    "        self.encoder.fc = nn.Sequential(nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # first layer\n",
    "                                        nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # second layer\n",
    "                                        self.encoder.fc,\n",
    "                                        nn.BatchNorm1d(dim, affine=False)) # output layer\n",
    "        self.encoder.fc[6].bias.requires_grad = False # hack: not use bias as it is followed by BN\n",
    "\n",
    "        if predictor:\n",
    "        # build a 2-layer predictor\n",
    "\n",
    "            self.predictor = nn.Sequential(nn.Linear(dim, pred_dim, bias=False),\n",
    "                                            nn.BatchNorm1d(pred_dim),\n",
    "                                            nn.ReLU(inplace=True), # hidden layer\n",
    "                                            nn.Linear(pred_dim, dim)) # output layer\n",
    "        else:\n",
    "            self.predictor = DirectFwd()\n",
    "\n",
    "        self.classification_head = nn.Linear(1536, 2)\n",
    "\n",
    "    def forward(self, ECG, PPG):\n",
    "        \"\"\"\n",
    "        Input:\n",
    "            x1: first views of images\n",
    "            x2: second views of images\n",
    "        Output:\n",
    "            p1, p2, z1, z2: predictors and targets of the network\n",
    "            See Sec. 3 of https://arxiv.org/abs/2011.10566 for detailed notations\n",
    "        \"\"\"\n",
    "\n",
    "        if not self.single_source_mode:\n",
    "            # compute features for one view\n",
    "            z1, features1 = self.encoder(ECG) # NxC\n",
    "            z2, features2 = self.encoder(PPG) # NxC\n",
    "\n",
    "            p1 = self.predictor(z1) # NxC\n",
    "            p2 = self.predictor(z2) # NxC\n",
    "            \n",
    "            class_pred1 = self.classification_head(features1)\n",
    "            class_pred2 = self.classification_head(features2)\n",
    "\n",
    "            return p1, p2, z1.detach(), z2.detach(), class_pred1, class_pred2\n",
    "        else:\n",
    "            z1, features1 = self.encoder(ECG) # NxC\n",
    "\n",
    "            p1 = self.predictor(z1) # NxC\n",
    "            \n",
    "            class_pred1 = self.classification_head(features1)\n",
    "\n",
    "            return p1, z1.detach(), class_pred1\n",
    "\n",
    "\n",
    "\n",
    "class Resnet34Head(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Resnet34Head,self).__init__()\n",
    "        self.conv0 = nn.Conv1d(1, 48, 80, 4)\n",
    "        self.bn0 = nn.BatchNorm1d(48)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.pool0 = nn.MaxPool1d(4)\n",
    "\n",
    "    def forward(self, x):\n",
    "        \n",
    "        out = self.conv0(x)\n",
    "        out = self.bn0(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.pool0(out)\n",
    "        return out\n",
    "\n",
    "\n",
    "class Resnet34Body(nn.Module):\n",
    "    def __init__(self, num_classes=2):\n",
    "        super(Resnet34Body,self).__init__()\n",
    "        self.num_classes = num_classes\n",
    "        self.stage0 = nn.Sequential(ResBlock(48, 0, 0),\n",
    "                                   ResBlock(48, 0, 1))\n",
    "        self.pool1 = nn.MaxPool1d(4)\n",
    "        self.stage1 = nn.Sequential(ResBlock(96, 1, 0),\n",
    "                                   ResBlock(96, 1, 1))\n",
    "        self.pool2 = nn.MaxPool1d(4)\n",
    "        self.stage2 = nn.Sequential(ResBlock(192, 2, 0),\n",
    "                                    ResBlock(192, 2, 1))\n",
    "        self.pool3 = nn.MaxPool1d(4)\n",
    "        self.stage3 = nn.Sequential(ResBlock(384, 3, 0),\n",
    "                                    ResBlock(384, 3, 1))\n",
    "\n",
    "        self.avgpool = nn.AvgPool1d(1)\n",
    "        self.fc = nn.Linear(384, self.num_classes)\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = self.stage0(x)\n",
    "        out = self.pool1(out)\n",
    "\n",
    "        out = self.stage1(out)\n",
    "        out = self.pool2(out)\n",
    "\n",
    "        out = self.stage2(out)\n",
    "        out = self.pool3(out)\n",
    "\n",
    "        out = self.stage3(out)\n",
    "\n",
    "        out = self.avgpool(out)\n",
    "        features = out.mean(dim=2)\n",
    "        out = self.fc(features)\n",
    "\n",
    "        return out, features\n",
    "\n",
    "\n",
    "class Res34SimSiamSplitHeads(nn.Module):\n",
    "    \"\"\"\n",
    "    Build a SimSiam model.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim=2048, pred_dim=512, predictor=True, single_source_mode=False, single_source_head=''):\n",
    "        \"\"\"\n",
    "        dim: feature dimension (default: 2048)\n",
    "        pred_dim: hidden dimension of the predictor (default: 512)\n",
    "        \"\"\"\n",
    "        super(Res34SimSiamSplitHeads, self).__init__()\n",
    "\n",
    "        # create the encoder\n",
    "        # num_classes is the output fc dimension, zero-initialize last BNs\n",
    "\n",
    "        self.single_source_mode = single_source_mode\n",
    "        self.single_source_head = single_source_head\n",
    "\n",
    "        if self.single_source_mode and self.single_source_head not in ['PPG', 'ECG']:\n",
    "            raise Exception('single_source_head must be either ECG or PPG')\n",
    "\n",
    "        self.ECG_head = Resnet34Head()\n",
    "        self.PPG_head = Resnet34Head()\n",
    "        self.encoder = Resnet34Body(num_classes=dim)\n",
    "\n",
    "        # build a 3-layer projector\n",
    "        prev_dim = self.encoder.fc.weight.shape[1]\n",
    "        self.encoder.fc = nn.Sequential(nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # first layer\n",
    "                                        nn.Linear(prev_dim, prev_dim, bias=False),\n",
    "                                        nn.BatchNorm1d(prev_dim),\n",
    "                                        nn.ReLU(inplace=True), # second layer\n",
    "                                        self.encoder.fc,\n",
    "                                        nn.BatchNorm1d(dim, affine=False)) # output layer\n",
    "        self.encoder.fc[6].bias.requires_grad = False # hack: not use bias as it is followed by BN\n",
    "\n",
    "        if predictor:\n",
    "        # build a 2-layer predictor\n",
    "            self.predictor = nn.Sequential(nn.Linear(dim, pred_dim, bias=False),\n",
    "                                            nn.BatchNorm1d(pred_dim),\n",
    "                                            nn.ReLU(inplace=True), # hidden layer\n",
    "                                            nn.Linear(pred_dim, dim)) # output layer\n",
    "        else:\n",
    "            self.predictor = DirectFwd()\n",
    "\n",
    "        self.classification_head = nn.Linear(384, 2)\n",
    "\n",
    "    def forward(self, ECG, PPG):\n",
    "        \"\"\"\n",
    "        Input:\n",
    "            x1: first views of images\n",
    "            x2: second views of images\n",
    "        Output:\n",
    "            p1, p2, z1, z2: predictors and targets of the network\n",
    "            See Sec. 3 of https://arxiv.org/abs/2011.10566 for detailed notations\n",
    "        \"\"\"\n",
    "        if not self.single_source_mode:\n",
    "            ECG_aft_head = self.ECG_head(ECG)\n",
    "            PPG_aft_head = self.PPG_head(PPG)\n",
    "\n",
    "            # compute features for one view\n",
    "            z1, features1 = self.encoder(ECG_aft_head) # NxC\n",
    "            z2, features2 = self.encoder(PPG_aft_head) # NxC\n",
    "\n",
    "            p1 = self.predictor(z1) # NxC\n",
    "            p2 = self.predictor(z2) # NxC\n",
    "            \n",
    "            class_pred1 = self.classification_head(features1)\n",
    "            class_pred2 = self.classification_head(features2)\n",
    "\n",
    "            return p1, p2, z1.detach(), z2.detach(), class_pred1, class_pred2\n",
    "\n",
    "        elif self.single_source_mode and self.single_source_head == 'PPG':\n",
    "            PPG_aft_head = self.PPG_head(PPG)\n",
    "\n",
    "            # compute features for one view\n",
    "            z2, features2 = self.encoder(PPG_aft_head) # NxC\n",
    "\n",
    "            p2 = self.predictor(z2) # NxC\n",
    "            \n",
    "            class_pred2 = self.classification_head(features2)\n",
    "\n",
    "            return p2, z2.detach(), class_pred2\n",
    "\n",
    "        elif self.single_source_mode and self.single_source_head == 'ECG':\n",
    "            ECG_aft_head = self.ECG_head(ECG)\n",
    "\n",
    "            # compute features for one view\n",
    "            z1, features1 = self.encoder(ECG_aft_head) # NxC\n",
    "\n",
    "            p1 = self.predictor(z1) # NxC\n",
    "            \n",
    "            class_pred1 = self.classification_head(features1)\n",
    "\n",
    "            return p1, z1.detach(), class_pred1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "4b91c6bc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:51.924832Z",
     "iopub.status.busy": "2024-09-15T23:49:51.924475Z",
     "iopub.status.idle": "2024-09-15T23:49:51.985270Z",
     "shell.execute_reply": "2024-09-15T23:49:51.984257Z"
    },
    "papermill": {
     "duration": 0.071442,
     "end_time": "2024-09-15T23:49:51.987211",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.915769",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "\n",
    "DIM1, DIM2 = 512, 128\n",
    "PREDICTOR = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "04c97996",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:52.004116Z",
     "iopub.status.busy": "2024-09-15T23:49:52.003783Z",
     "iopub.status.idle": "2024-09-15T23:49:52.207811Z",
     "shell.execute_reply": "2024-09-15T23:49:52.206608Z"
    },
    "papermill": {
     "duration": 0.21528,
     "end_time": "2024-09-15T23:49:52.210112",
     "exception": false,
     "start_time": "2024-09-15T23:49:51.994832",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model params: 2.57 M\n"
     ]
    }
   ],
   "source": [
    "model = Res34SimSiam(DIM1, DIM2, predictor=PREDICTOR)\n",
    "model.to(device)\n",
    "\n",
    "# show model size\n",
    "model_size = 0\n",
    "for param in model.parameters():\n",
    "    model_size += param.data.nelement()\n",
    "print(\"Model params: %.2f M\" % (model_size / 1024 / 1024))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "313d67b4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:52.227376Z",
     "iopub.status.busy": "2024-09-15T23:49:52.226967Z",
     "iopub.status.idle": "2024-09-15T23:49:52.232290Z",
     "shell.execute_reply": "2024-09-15T23:49:52.231364Z"
    },
    "papermill": {
     "duration": 0.016275,
     "end_time": "2024-09-15T23:49:52.234242",
     "exception": false,
     "start_time": "2024-09-15T23:49:52.217967",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def cos_loss(p, z):\n",
    "    p = F.normalize(p, dim=1) # l2-normalize \n",
    "    z = F.normalize(z, dim=1) # l2-normalize \n",
    "    return -(p*z).sum(dim=1).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "cd83d85b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:52.250607Z",
     "iopub.status.busy": "2024-09-15T23:49:52.250302Z",
     "iopub.status.idle": "2024-09-15T23:49:53.462899Z",
     "shell.execute_reply": "2024-09-15T23:49:53.462050Z"
    },
    "papermill": {
     "duration": 1.223467,
     "end_time": "2024-09-15T23:49:53.465344",
     "exception": false,
     "start_time": "2024-09-15T23:49:52.241877",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "PPG_LR = 1e-4\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=PPG_LR)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "2b3c7531",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:53.483779Z",
     "iopub.status.busy": "2024-09-15T23:49:53.482755Z",
     "iopub.status.idle": "2024-09-15T23:49:53.487400Z",
     "shell.execute_reply": "2024-09-15T23:49:53.486463Z"
    },
    "papermill": {
     "duration": 0.015653,
     "end_time": "2024-09-15T23:49:53.489377",
     "exception": false,
     "start_time": "2024-09-15T23:49:53.473724",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "LAMBDA = 1.0\n",
    "EPOCHS = 30"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "008e150c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:49:53.505816Z",
     "iopub.status.busy": "2024-09-15T23:49:53.505510Z",
     "iopub.status.idle": "2024-09-15T23:59:14.550088Z",
     "shell.execute_reply": "2024-09-15T23:59:14.549088Z"
    },
    "papermill": {
     "duration": 561.059706,
     "end_time": "2024-09-15T23:59:14.556735",
     "exception": false,
     "start_time": "2024-09-15T23:49:53.497029",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8f15768e5f36495db71e8ac5e55c066b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/30 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "total_losses = []\n",
    "mse_losses = []\n",
    "simsam_losses = []\n",
    "\n",
    "for epoch in tqdm(range(EPOCHS)):\n",
    "    for batch in train_loader:\n",
    "        ecg, ppg, labels = batch\n",
    "\n",
    "        ecg = ecg.to(device)\n",
    "        ppg = ppg.to(device)\n",
    "        labels = labels.to(device)\n",
    "\n",
    "        p1, p2, z1, z2, ecg_reg, ppg_reg = model(ecg, ppg)\n",
    "        simsam_loss = cos_loss(p1, z2) / 2 + cos_loss(p2, z1) / 2\n",
    "        ecg_mse_loss = F.mse_loss(ecg_reg, labels)\n",
    "        ppg_mse_loss = F.mse_loss(ppg_reg, labels)\n",
    "\n",
    "        total_loss = simsam_loss * LAMBDA + ecg_mse_loss + ppg_mse_loss\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "        total_loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "        total_losses.append(total_loss.item())\n",
    "\n",
    "        mse_loss = ecg_mse_loss + ppg_mse_loss\n",
    "        mse_losses.append(mse_loss.item())\n",
    "\n",
    "        simsam_losses.append(simsam_loss.item())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "25db76ad",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-15T23:59:14.574186Z",
     "iopub.status.busy": "2024-09-15T23:59:14.573811Z",
     "iopub.status.idle": "2024-09-15T23:59:15.244802Z",
     "shell.execute_reply": "2024-09-15T23:59:15.243784Z"
    },
    "papermill": {
     "duration": 0.682133,
     "end_time": "2024-09-15T23:59:15.246930",
     "exception": false,
     "start_time": "2024-09-15T23:59:14.564797",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.subplot(3, 1, 1)\n",
    "plt.plot(total_losses)\n",
    "plt.title(\"Joint Loss\")\n",
    "\n",
    "plt.subplot(3, 1, 2)\n",
    "plt.plot(mse_losses)\n",
    "plt.title(\"MSE Loss\")\n",
    "\n",
    "plt.subplot(3, 1, 3)\n",
    "plt.plot(simsam_losses)\n",
    "plt.title(\"Agreement Loss\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kaggle": {
   "accelerator": "gpu",
   "dataSources": [
    {
     "datasetId": 5711874,
     "sourceId": 9407429,
     "sourceType": "datasetVersion"
    }
   ],
   "dockerImageVersionId": 30762,
   "isGpuEnabled": true,
   "isInternetEnabled": true,
   "language": "python",
   "sourceType": "notebook"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 590.970581,
   "end_time": "2024-09-15T23:59:17.647370",
   "environment_variables": {},
   "exception": null,
   "input_path": "__notebook__.ipynb",
   "output_path": "__notebook__.ipynb",
   "parameters": {},
   "start_time": "2024-09-15T23:49:26.676789",
   "version": "2.6.0"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "133f1fc24af847cfb59579518a36a194": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_44392b3577a4434883cd4c0b16170d9b",
       "max": 30.0,
       "min": 0.0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_a57a6faff9d54b0c84240e2588ee7633",
       "value": 30.0
      }
     },
     "23166c053f634c3e8f0a213ba54ac0d3": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "23c2b43b029b438a9b8d6b6e05a60a0c": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_f350193866384b31a12dce5f8b491840",
       "placeholder": "​",
       "style": "IPY_MODEL_4aab8b4a7e544bd584ea28b58d22873c",
       "value": " 30/30 [09:21&lt;00:00, 18.64s/it]"
      }
     },
     "259255f77f53428b918f64bc18adf76a": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_eb328e642bc1418599f053d95f4ca1d5",
       "placeholder": "​",
       "style": "IPY_MODEL_300cbe46546649c6ba08101cece949a2",
       "value": "100%"
      }
     },
     "300cbe46546649c6ba08101cece949a2": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "32e7d4f07858411e9aac2e0d433b613d": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "35cd80b984c74fae9046bf06acc5d4da": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "44392b3577a4434883cd4c0b16170d9b": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "4aab8b4a7e544bd584ea28b58d22873c": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "5a0607fba40a4310b60b7b7eb0902104": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_c7edfcad91414947b3b17098141c2de0",
       "placeholder": "​",
       "style": "IPY_MODEL_32e7d4f07858411e9aac2e0d433b613d",
       "value": "100%"
      }
     },
     "6073297b2678434f85aab49627a58a38": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "61b57f5ceeb844c28b6123c3d52f3c75": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_d8c72f35d17e4c6ea7d2bba93a896fc4",
       "max": 1.0,
       "min": 0.0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_23166c053f634c3e8f0a213ba54ac0d3",
       "value": 1.0
      }
     },
     "676f5461f3874bb9a9ac1d5934884170": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "72400e131c55490c9a8e7beb51015b61": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_ed3c9da60484433591307973dbfa376b",
       "placeholder": "​",
       "style": "IPY_MODEL_6073297b2678434f85aab49627a58a38",
       "value": "100%"
      }
     },
     "73f00a30825b4394a37a6d7a39529847": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "79b86ad6ae8a4d39b91c1db3a87b73ca": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "7bf26fd06b7b4201bd6adb373755326b": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_72400e131c55490c9a8e7beb51015b61",
        "IPY_MODEL_c94b5be1e53f44c4a4d095e17539b89d",
        "IPY_MODEL_f6877b820b3d414e8fc629876a9653a1"
       ],
       "layout": "IPY_MODEL_35cd80b984c74fae9046bf06acc5d4da"
      }
     },
     "8f15768e5f36495db71e8ac5e55c066b": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_5a0607fba40a4310b60b7b7eb0902104",
        "IPY_MODEL_133f1fc24af847cfb59579518a36a194",
        "IPY_MODEL_23c2b43b029b438a9b8d6b6e05a60a0c"
       ],
       "layout": "IPY_MODEL_8fc3b65343654bd68430ac066e20590b"
      }
     },
     "8fc3b65343654bd68430ac066e20590b": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "993d843fde5a441b94a71059d1165339": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "a57a6faff9d54b0c84240e2588ee7633": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "c7edfcad91414947b3b17098141c2de0": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "c94b5be1e53f44c4a4d095e17539b89d": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_79b86ad6ae8a4d39b91c1db3a87b73ca",
       "max": 12.0,
       "min": 0.0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_cabe226897b446a2b211fe8a56c10eaa",
       "value": 12.0
      }
     },
     "c9f0ed8c098540cc997d0c5990ae4358": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "DescriptionStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "DescriptionStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "description_width": ""
      }
     },
     "cabe226897b446a2b211fe8a56c10eaa": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "ccf06125ff8c45bea76507aef189c570": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_676f5461f3874bb9a9ac1d5934884170",
       "placeholder": "​",
       "style": "IPY_MODEL_73f00a30825b4394a37a6d7a39529847",
       "value": " 1/1 [00:01&lt;00:00,  1.18s/it]"
      }
     },
     "d8c72f35d17e4c6ea7d2bba93a896fc4": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "d9d817444e2f4a0299cb21059f84c2b2": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_259255f77f53428b918f64bc18adf76a",
        "IPY_MODEL_61b57f5ceeb844c28b6123c3d52f3c75",
        "IPY_MODEL_ccf06125ff8c45bea76507aef189c570"
       ],
       "layout": "IPY_MODEL_de81a3f828ea42e68a42b0a50b3319de"
      }
     },
     "de81a3f828ea42e68a42b0a50b3319de": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "eb328e642bc1418599f053d95f4ca1d5": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "ed3c9da60484433591307973dbfa376b": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "f350193866384b31a12dce5f8b491840": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "1.2.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "1.2.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "overflow_x": null,
       "overflow_y": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "f6877b820b3d414e8fc629876a9653a1": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "1.5.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_tooltip": null,
       "layout": "IPY_MODEL_993d843fde5a441b94a71059d1165339",
       "placeholder": "​",
       "style": "IPY_MODEL_c9f0ed8c098540cc997d0c5990ae4358",
       "value": " 12/12 [00:14&lt;00:00,  1.21s/it]"
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
